use std::{collections::HashMap, sync::Arc};

use rcu::RcuLock;

use crate::{
    CompleterPosFrom, CompleterSuggestion, MonError, MonResult, Monitor, MonitorCommand,
    MonitorPrinter, Protocol,
};

struct MonitorHelp {
    command_hash: Arc<RcuLock<HashMap<String, Arc<dyn MonitorCommand + Sync + Send>>>>,
}

impl MonitorCommand for MonitorHelp {
    fn mon_protocol_exec(&self, _: &Protocol) -> MonResult<Protocol> {
        Err(MonError::PermProtocol)
    }

    #[allow(clippy::string_add)]
    fn mon_readline_exec(
        &self,
        args: &HashMap<String, String>,
        printer: &MonitorPrinter,
    ) -> MonResult<()> {
        let lock = self.command_hash.read().unwrap();
        if args.is_empty() {
            for (k, d) in lock.iter() {
                let help = d.mon_readline_help();

                printer.print(format!("{:<17} - {}", k, help));
            }
            return Ok(());
        }

        if args.len() != 1 {
            return Err(MonError::InvalidArgsType);
        }

        let command = args.get("1").ok_or(MonError::InvalidArgsType)?;
        let data = lock.get(command).ok_or(MonError::NoCommand)?;
        let help = data.mon_readline_help();
        printer.print(help);

        let long_help = data.mon_readline_long_help();
        if let Some(lh) = long_help {
            printer.print("\n".to_string() + lh.as_str());
        }
        Ok(())
    }

    fn mon_readline_completer(&self, args: &[&str], is_space: bool) -> Option<CompleterSuggestion> {
        let mut v = vec![];
        let lock = self.command_hash.read().unwrap();
        if args.is_empty() {
            debug_assert!(is_space);
            for (k, _) in lock.iter() {
                v.push(k.clone());
            }
            v.sort();
            return Some(CompleterSuggestion::create(CompleterPosFrom::Deafult, v, true));
        }

        if args.len() == 1 && !is_space {
            let word = args[0];
            for (k, _) in lock.iter() {
                if k.starts_with(word) {
                    v.push(k.clone());
                }
            }
            v.sort();
            return Some(CompleterSuggestion::create(CompleterPosFrom::Deafult, v, true));
        }
        None
    }

    fn mon_readline_help(&self) -> String {
        String::from("打印帮助信息")
    }

    fn mon_readline_long_help(&self) -> Option<String> {
        Some(String::from("help [command] - 打印所有命令的 help 信息"))
    }
}

impl Monitor {
    pub(crate) fn register_help(&self) {
        let rhelp = Arc::new(MonitorHelp { command_hash: self.commnad_hash_clone() });
        self.register_command("help", rhelp).unwrap();
    }
}
